﻿// Nail.WindowsContextMenu Library
// Nail framework
//
// Copyright © Frank Nagl, 2008
// admin@franknagl.de
// www.franknagl.de
//
namespace Nail
{
    using Microsoft.Win32;
    using System;
    using System.Windows.Forms;
    using System.Security.Permissions;
    using System.Security;

    /// <summary>
    /// Provides static functions to add and remove Windows context menu entries for
    /// special file formats.
    /// </summary>
    //[RegistryPermissionAttribute(SecurityAction.Demand, Unrestricted = true)]
    public static class WindowsContextMenu
    {
        //f.e. just for directories: "Folder\\shell\\NewMenuOption";
        //const string NewMenuOption = "\\shell\\NewMenuOption";
        //const string Command = "\\shell\\NewMenuOption\\command";

        /// <summary>
        /// Adds a Windows context menu entry for directories.
        /// </summary>
        /// <param name="programName">The name of the program,
        /// which will be shown at the context menu.</param>
        /// <param name="programPath">The program path,
        /// where the context menu entry will be linked to.</param>
        /// <param name="parameters">The parameter(s).</param>
        /// <param name="NewMenuOption">The new menu option string for the registry.</param>
        public static void AddDirectoryEntry(string programName, string programPath,
            string parameters, string NewMenuOption)
        {
            RegistryKey regmenu;
            RegistryKey regcmd = null;

            try
            {
                //Create context menu
                regmenu = Registry.ClassesRoot.CreateSubKey("Folder" + NewMenuOption);
                regmenu.SetValue("", programName);
                regcmd = Registry.ClassesRoot.CreateSubKey("Folder" + NewMenuOption + 
                    "\\Command");
                regcmd.SetValue("", programPath + parameters);

                regmenu.Close();
                regcmd.Close();

            }
            catch (Exception ex)
            {
                MessageBox.Show("Folder:\n\n" + ex.ToString());
            }
        }

        /// <summary>
        /// Adds Windows context menu entries.
        /// </summary>
        /// <param name="formats">The list of file formats,
        /// which will get the context menu entries.</param>
        /// <param name="programName">The name of the program,
        /// which will be shown at the context menu.</param>
        /// <param name="programPath">The program path,
        /// where the context menu entry will be linked to.</param>
        /// <param name="parameters">The parameter(s).</param>
        /// <param name="NewMenuOption">The new menu option string for the registry.</param>
        public static void AddEntries(string[] formats, string programName,
            string programPath, string parameters, string NewMenuOption)
        {
            RegistryKey regmenu;
            RegistryKey regcmd = null;
            string name = "nil";
            for (int i = 0; i < formats.Length; i++)
            {
                try
                {                    
                    regmenu = Registry.ClassesRoot.OpenSubKey(formats[i], false);
                    //If format already exists, get its value name, ...
                    if (regmenu == null || 
                        (name = (String)regmenu.GetValue("")) == null)
                    {
                        name = formats[i].Substring(1) + "file";
                        regmenu = Registry.ClassesRoot.CreateSubKey(formats[i]);
                        regmenu.SetValue("", name);
                    }
                    regmenu.Close();

                    //Create context menu
                    regmenu = Registry.ClassesRoot.CreateSubKey(name + NewMenuOption);
                    regmenu.SetValue("", programName);
                    regcmd = Registry.ClassesRoot.CreateSubKey(name + NewMenuOption +
                    "\\Command");
                    regcmd.SetValue("", programPath + parameters);

                    regmenu.Close();
                    regcmd.Close();

                }
                catch (ArgumentException ex)
                {
                    // RegistryPermissionAccess.AllAccess can not be used as a parameter for GetPathList.
                    MessageBox.Show(name + ":\n\n" + "An ArgumentException occured as a result of using AllAccess.  "
                        + "AllAccess cannot be used as a parameter in GetPathList because it represents more than one "
                        + "type of registry variable access : \n" + ex);
                }
                catch (SecurityException ex)
                {
                    // RegistryPermissionAccess.AllAccess can not be used as a parameter for GetPathList.
                    MessageBox.Show(name + ":\n\n" + "An ArgumentException occured as a result of using AllAccess.  " + ex);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(name + ":\n\n" + ex.ToString());
                }
            }
        }

        /// <summary>
        /// Removes the Windows context menu entries of the passed file formats.
        /// </summary>
        /// <param name="formats">The list of file formats,
        /// where the context menu entries will be removed.</param>
        /// <param name="checkExistence">If <c>true</c> it will
        /// be checked if the entry exists in the win registry before trying removing.</param>
        /// <param name="NewMenuOption">The new menu option string for the registry.</param>
        public static void RemoveEntries(string[] formats, bool checkExistence,
            string NewMenuOption)
        {
            RegistryKey reg;
            string name = "nil";
            for (int i = 0; i < formats.Length; i++)
            {
                try
                {                    
                    reg = Registry.ClassesRoot.OpenSubKey(formats[i], false);
                    //If format already exists, get its value name, otherwise return.
                    if (reg != null)
                        name = (String)reg.GetValue("");
                    else
                        return;
                    reg.Close();

                    //Delete Windows context menu entry
                    reg = Registry.ClassesRoot.OpenSubKey(name + NewMenuOption + 
                        "\\Command");
                    if (!checkExistence || reg != null)
                    {
                        Registry.ClassesRoot.DeleteSubKey(name + NewMenuOption + 
                            "\\Command");
                        Registry.ClassesRoot.DeleteSubKey(name + NewMenuOption);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(name + ":\n\n" + ex.ToString());
                }
            }
        }

        /// <summary>
        /// Removes the Windows context menu entries of the passed file formats.
        /// </summary>
        /// <param name="checkExistence">If <c>true</c> it will
        /// be checked if the entry exists in the win registry before trying removing.</param>
        /// <param name="NewMenuOption">The new menu option string for the registry.</param>
        public static void RemoveDirectoryEntry(bool checkExistence,
            string NewMenuOption)
        {
            RegistryKey reg;
            try
            {
                //Delete Windows context menu entry for folders
                reg = Registry.ClassesRoot.OpenSubKey("Folder" + NewMenuOption +
                    "\\Command");
                if (!checkExistence || reg != null)
                {
                    Registry.ClassesRoot.DeleteSubKey("Folder" + NewMenuOption +
                        "\\Command");
                    Registry.ClassesRoot.DeleteSubKey("Folder" + NewMenuOption);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Folder:\n\n" + ex.ToString());
            }
        }

        ///// <summary>
        ///// Checks the security.
        ///// </summary>
        ///// <param name="menuName">Name of the menu.</param>
        ///// <param name="command">The command.</param>
        //public static void CheckSecurity(string menuName, string command)
        //{

        //    //check registry permissions
        //    RegistryPermission regPerm;
        //    regPerm = new RegistryPermission(RegistryPermissionAccess.Write, "HKEY_CLASSES_ROOT\\" + menuName);
        //    regPerm.AddPathList(RegistryPermissionAccess.Write, "HKEY_CLASSES_ROOT\\" + command);
        //    regPerm.Demand();

        //}
    }
}
